//
//  TemplateClass.h
//  HelloWorld
//
//  Created by Kevin Tang on 11/12/14.
//  Copyright (c) 2014年 Kevin Tang. All rights reserved.
//

#ifndef __HelloWorld__TemplateClass__
#define __HelloWorld__TemplateClass__
#include <iostream>
#include <vector>
#include <deque>
#include <stdexcept>

//=================类模板====================

template <typename T>
class Stack  {
private:
    std::vector<T> elems;//元素
    
public:
   // Stack();
   // Stack(Stack<T> const&);//拷贝构造
   // Stack<T>& operator= (Stack<T> const&);//赋值运算符重载
    
    void push(T const&);
    void pop();
    T top() const;
    bool empty() const{
        return elems.empty();
    }
};

template <typename T>
void Stack<T>::push(T const& elem)
{
    elems.push_back(elem);//追加在未尾
}

template <typename T>
void Stack<T>::pop()
{
    if(elems.empty()){
        throw std::out_of_range("Stack< >::pop empty stack");
    }
    elems.pop_back();//移除最后一个元素
}

template <typename T>
T Stack<T>::top()const
{
    if(elems.empty()){
        throw std::out_of_range("Stack< >::top empty stack");
    }
    return elems.back();//返回最后一个元素
}


//=================类模板的特化====================

template <>//表示要特化一个类，这是一个声明
//注意下面的Stack要跟一个尖括号<>,并在尖括号内，写出要特化的类型参数,由于我们把所有出现T的地方，都替换成了std::string.所以这叫全特化.
//还有一种叫偏特化，即只对部分类型参数特化，而保留一些不特化。
class Stack<std::string> {
private:
    //元素 [注意这里我们用的是std::deque,而不是std::vector,只是表示特化可以与原模板类有相当程度的区别]
    std::deque <std::string> elems;
    
public:
    // Stack();
    // Stack(Stack<T> const&);//拷贝构造
    // Stack<T>& operator= (Stack<T> const&);//赋值运算符重载
    
    void push(std::string const&);
    void pop();
    std::string top() const;
    bool empty() const{
        return elems.empty();
    }
};

//成员函数的定义时，Stack后要加<>号，并写入特化类型参数,而不像普通的函数实现那样，直接写类名.
//这里的 void Stack<std::string> 和前面的 class Stack<std::string> 写法是同理的，即都要加<std::string>
//
void Stack<std::string>::push(std::string const& elem)
{
    elems.push_back(elem);//追加在未尾
}


void Stack<std::string>::pop()
{
    if(elems.empty()){
        throw std::out_of_range("Stack< >::pop empty stack");
    }
    elems.pop_back();//移除最后一个元素
}


std::string Stack<std::string>::top()const
{
    if(elems.empty()){
        throw std::out_of_range("Stack< >::top empty stack");
    }
    return elems.back();//返回最后一个元素
}

//=================偏特化|局部特化|部分特化===============

template < typename T1 ,typename T2 >
class MyClass{//这个是一通用模板类


};
//[A]由于我们把T1,T2,全部相应的确定为 int,double了，所以下面的template <> ，尖括号中就不需要写东西了。
template <>
class MyClass<int,double>{

};

//[B]编特化一次,表示上面的T1,T2这两个模板参数变成同一个类型的参数，即T
template <typename T>
class MyClass<T,T> {

};
//[C]第二个模板参数特化,第一个参数，由用户使用时自己选择
template <typename T>
class MyClass<T,int>{

};
//[D]
template <typename T1,typename T2>
class MyClass<T1* ,T2*>{//表示把T1,T2偏特化为指针类型
    
};
//=============这些使用的例子，说明使用上面的那些模板==============
//MyClass<int, int> a;//这个例子，会产生二义性，它与B,C,都匹配
//MyClass<float * ,float *> e;//产生二义性，因为它匹配通用模板类，和B.(解除这里声明的二义性在下面)
MyClass<int,double> b;//将使用A
MyClass<float, float> c;//将使用B
MyClass<int*, float*> d;//将使用D,因为它的两个参数不一样

//=======为了解决上述的二义性我们提供另一个模板==========
//E
template <typename T>
class MyClass<T*,T*> {
    
};

//注意模板声明，与使用的先后位置,
MyClass<float * ,float *> e;

template <typename T >
class OtherClass;

template <typename T >
class OtherClass <T []>{
private:
    int i;
public:
    OtherClass(T const& paramter);//{ i = paramter;}
    int getInt();
//    {
//        return i;
//    }
    void setInt(int j);
//    {
//        i = j;
//    }
};

template <typename T >
OtherClass<T [] >::OtherClass(T const& paramter)
{
    i = paramter;
}

template <typename T >
int OtherClass <T []>::getInt()
{
    return i;
}
template <typename T >
void  OtherClass <T []>::setInt(int j)
{
    i = j;
}



#endif /* defined(__HelloWorld__TemplateClass__) */
